package com.qiwenshare.stock.controller;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson2.JSON;
import com.qiwenshare.common.result.RestResult;
import com.qiwenshare.stock.analysis.ReplayOperation;
import com.qiwenshare.stock.analysis.TechnologyAnalysis;
import com.qiwenshare.stock.analysis.indicator.KDJAnalysis;
import com.qiwenshare.stock.api.*;
import com.qiwenshare.stock.common.DingTalkUtil;
import com.qiwenshare.stock.common.HttpsUtils;
import com.qiwenshare.stock.common.TableData;
import com.qiwenshare.stock.common.TableQueryBean;
import com.qiwenshare.stock.common.TaskProcess;
import com.qiwenshare.stock.constant.StockTaskTypeEnum;
import com.qiwenshare.stock.domain.*;
import com.qiwenshare.stock.executor.ReplayRunnable;
import com.qiwenshare.stock.executor.StockExecutor;
import com.qiwenshare.stock.websocket.StockWebsocket;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.Data;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.persistence.Column;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

@Slf4j
@Tag(name = "股票")
@RequestMapping("/stock")
@RestController
public class StockJobController {
    public static int totalCount = 0;
    public static volatile int updateCount = 0;

    /**
     * 当前模块
     */

    private static final int NTHREADS = 20;
    public static ExecutorService stockReplayexec = Executors.newFixedThreadPool(NTHREADS);
    public static ExecutorService stockListexec = Executors.newFixedThreadPool(NTHREADS);
    @Resource
    IStockDIService stockDIService;
    @Resource
    IStockTimeInfoService stockTimeInfoService;
    @Resource
    IStockDayInfoService stockDayInfoService;
    @Resource
    IStockWeekInfoService stockWeekInfoService;
    @Resource
    IStockMonthInfoService stockMonthInfoService;
    @Resource
    StockExecutor stockExecutor;
    @Resource
    IStockBidService stockBidService;
    @Resource
    IStockOptionalService stockOptionalService;
    @Resource
    IReplayService replayService;
    @Resource
    IEchnicalaspectService echnicalaspectService;
    @Resource
    IAbnormalaActionService abnormalaActionService;

    @Resource
    IGuessDailyService guessDailyService;

    @SneakyThrows
    @Operation(summary = "所有股票数据回测")
    @RequestMapping("/totalstockbacktest")
    @ResponseBody
    public RestResult<String> totalStockBackTest() {
        RestResult<String> restResult = new RestResult<String>();
        //1、获取所有股票列表
        List<StockBean> stocklist = stockDIService.selectTotalStockList();
        ReplayRunnable.totalCount = stocklist.size();
        ReplayRunnable.updateCount = 0;
        for (StockBean stockBean : stocklist) {
            Runnable task = new ReplayRunnable(stockBean, replayService, stockDayInfoService, guessDailyService);
            stockReplayexec.execute(task);
        }
        while(ReplayRunnable.totalCount > ReplayRunnable.updateCount) {
            Thread.sleep(10000);
        }

        restResult.setSuccess(true);
        return restResult;


    }

    @Operation(summary = "检测上证股票数据是否有需要更新")
    @RequestMapping("/checkstockisupdate")
    @ResponseBody
    public RestResult<String> checkStockIsUpdate() {
        RestResult<String> restResult = new RestResult<String>();
        List<StockBean> stockList = stockDIService.selectTotalStockList();
        List<StockBean> jsonArr = stockDIService.getStockListByScript();
        List<StockBean> stockBeanList = new ArrayList<StockBean>();
        for (int i = 0; i < jsonArr.size(); i++) {
            StockBean stockStr = jsonArr.get(i);
            stockBeanList.add(stockStr);
        }

        List<StockBean> stockBeanList1 = new ArrayList<>();
        for (int i = 0; i < stockBeanList.size(); i++) {
            StockBean stockBean = new StockBean();
            if (!stockList.contains(stockBeanList.get(i))) {
                stockBean.setStockNum(stockBeanList.get(i).getStockNum());
                stockBean.setStockName(stockBeanList.get(i).getStockName());
                stockBeanList1.add(stockBean);
            }
        }
        if (stockBeanList1.size() > 0) {
            restResult.setData(JSON.toJSONString(stockBeanList1));

            restResult.setSuccess(true);
            return restResult;
        }
        restResult.setData("暂无新增股票信息");

        restResult.setSuccess(false);
        return restResult;

    }

    @Operation(summary = "更新股票列表")
    @RequestMapping("/updatestocklist")
    @ResponseBody
    public RestResult<String> updateStockList() {
        stockDIService.createStockInfoTable();
        RestResult<String> restResult = new RestResult<String>();
        List<StockBean> stockBeanList = stockDIService.getStockListByScript();
        //新增股票列表
        List<StockBean> newStockList = stockDIService.getNoExistStockList(stockBeanList);
        totalCount = newStockList.size();
        updateCount = 0;
        if (newStockList.size() > 0) {
            stockDIService.insertStockList(newStockList);
            for (StockBean stockBean : newStockList) {
                stockListexec.execute(new Runnable() {
                    @Override
                    public void run() {
                        TaskProcess taskProcess = new TaskProcess();
                        taskProcess.setTaskId(0);
                        synchronized (StockJobController.class) {
                            updateCount++;
                        }
                        taskProcess.setCompleteCount(updateCount);
                        taskProcess.setTotalCount(totalCount);

                        String stockNum = stockBean.getStockNum();
                        EchnicalaspectBean echnicalaspect = new EchnicalaspectBean(stockNum);
                        AbnormalactionBean abnormalactionBean = new AbnormalactionBean(stockNum);
                        StockBidBean stockBidBean = new StockBidBean(stockNum);
                        echnicalaspectService.insertEchnicalaspect(echnicalaspect);
                        abnormalaActionService.insertAbnormalaAction(abnormalactionBean);
                        stockBidService.insertStockBid(stockBidBean);
                        taskProcess.setTaskInfo("股票列表更新,当前正在更新项为：" + stockBean.getStockName() +"(" + stockBean.getStockNum() + "), 完成进度：" + updateCount + "/" + totalCount);
                        taskProcess.setRunTask(totalCount != updateCount);
                        StockWebsocket.pushTaskProcess(taskProcess);
                    }
                });

            }

            restResult.setData("正在更新股票数量：" + newStockList.size());
        } else {
            restResult.setData("暂无可更新股票");
        }

        restResult.setSuccess(true);

        return restResult;
    }

    /**
     * 更新股票数据
     *
     * @return
     */
    @SneakyThrows
    @Operation(summary = "更新股票详情")
    @RequestMapping("/updatestocktimeinfo")
    @ResponseBody
    public RestResult<String> updateStockTimeInfo() {
        RestResult<String> restResult = new RestResult<String>();
        //1、获取所有股票列表
        List<StockBean> stocklist = stockDIService.selectTotalStockList();
        stockExecutor.start(stocklist);
        while(StockExecutor.totalCount != StockExecutor.updateCount) {
            Thread.sleep(10000);
        }
        restResult.setSuccess(true);
        return restResult;
    }



    @Operation(summary = "停止更新股票信息")
    @RequestMapping("/stopupdatetaskbytype")
    @ResponseBody
    public RestResult<String> stopUpdateTaskByType(int taskType) {
        RestResult<String> restResult = new RestResult<String>();

        StockTaskTypeEnum enum1 = null;

        try {
            Boolean isStopSuccess = stockExecutor.stop();
            if (isStopSuccess) {
                StockWebsocket.pushTaskState("任务已经停止", false);
                restResult.setData("任务停止成功");
            } else {
                StockWebsocket.pushTaskState("不要重复停止", false);
                restResult.setData("暂无任务可以停止");
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        StockWebsocket.pushTaskState("任务已经停止", false);

        restResult.setSuccess(true);
        return restResult;
    }

    @Operation(summary = "停止更新股票分时信息")
    @RequestMapping("/stopupdatestocktimedata")
    @ResponseBody
    public RestResult<String> stopUpdateStockTimeData() {
        RestResult<String> restResult = new RestResult<String>();

        try {
            Boolean isStopSuccess = new StockExecutor().stop();
            if (isStopSuccess) {
                StockWebsocket.pushTaskState("任务已经停止", false);
                restResult.setData("任务停止成功");
            } else {
                StockWebsocket.pushTaskState("不要重复停止，小心我打你", false);
                restResult.setData("暂无任务可以停止");
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("停止成功！");

        restResult.setSuccess(true);
        return restResult;
    }

    @Operation(summary = "数据猜想")
    @RequestMapping("/guessdaily")
    @ResponseBody
    public RestResult<String> guessdaily() {
        RestResult<String> restResult = new RestResult<String>();

        List<StockBean> stocklist = stockDIService.selectTotalStockList();

        for(StockBean stockBean : stocklist) {
            stockReplayexec.submit(() -> {
                List<StockDayInfo> stockDayInfoList = stockDayInfoService.getStockdaybar(stockBean.getStockNum());
                if(CollectionUtil.isEmpty(stockDayInfoList)) {
                    return;
                }
                if(stockDayInfoList.size() > 20) {
                    stockDayInfoList = stockDayInfoList.subList(stockDayInfoList.size() - 21, stockDayInfoList.size() - 1);
                }

                for(StockDayInfo info : stockDayInfoList) {
                    TechnologyAnalysis kdjAnalysis = new KDJAnalysis();
                    ReplayBean kdjReplayBean = kdjAnalysis.getOperation(ListUtil.of(info), stockBean);
                    if(kdjReplayBean != null && (kdjReplayBean.getLiteBuy() == 1 || kdjReplayBean.getLiteSell() == 1)) {

                        if(guessDailyService.exist(stockBean.getStockNum(), info.getDate())) continue;
                        guessDailyService.insertGuessDaily(new GuessDailyBean(){{
                            setStockNum(stockBean.getStockNum());
                            setCreateTime(new Date());
                            setLiteSell(kdjReplayBean.getLiteSell());
                            setLiteBuy(kdjReplayBean.getLiteBuy());
                            setPriceDate(info.getDate());
                            setK(info.getK());
                            setD(info.getD());
                            setJ(info.getJ());
                            setCci(info.getCci());
                            setStockNum(stockBean.getStockName());
                        }});
                    }
                }

            });
        }

        restResult.setSuccess(true);
        return restResult;
    }

    @Operation(summary = "检测上证股票实时数据")
    @RequestMapping("/getshstock")
    @ResponseBody
    public String getShStock(){
        String result = "";
        String url = "http://yunhq.sse.com.cn:32041//v1/sh1/list/self/000001_000016_000010_000009_000300&select=code%2Cname%2Clast%2Cchg_rate%2Camount%2Copen%2Cprev_close&_=1585456053043";
        try {
            result = IOUtils.toString(HttpsUtils.doGet(url), "UTF-8");
        } catch (IOException e) {
            e.printStackTrace();
        }
        return result;
    }

    @Operation(summary = "发送回测数据到钉钉")
    @RequestMapping("/sendStockBackTest")
    @ResponseBody
    public RestResult<String> sendStockBackTest() {
        RestResult<String> restResult = new RestResult<String>();
        //1、获取所有股票列表
        log.info(DateUtil.format(new Date(), "yyyy-MM-dd"));
        String date = DateUtil.format(new Date(), "yyyy-MM-dd");
        List<ReplayBean> list = replayService.selectReplayListByDate(date, 0, 100);
        List<StockMsg> msgList = new ArrayList<>();
        for(ReplayBean item : list) {
            if(!item.getStockNum().startsWith("60")) {
                continue;
            }
            List<StockDayInfo> stockDayInfos = stockDayInfoService.selectStockDayInfoList(new StockBean() {{
                setStockNum(item.getStockNum());
            }});

            StockBean stockBean = stockDIService.getStockInfoById(item.getStockNum());

            if(CollectionUtil.isNotEmpty(stockDayInfos)) {
                StockDayInfo lastDayInfo = stockDayInfos.get(stockDayInfos.size() - 1);
                StockMsg stockMsg = new StockMsg();
                BeanUtil.copyProperties(item, stockMsg);
                BeanUtil.copyProperties(lastDayInfo, stockMsg);
                stockMsg.setStockName(stockBean.getStockName());
                msgList.add(stockMsg);
            }
        }

        // 计算出需要发送的批次数量
        int batchSize = 20;
        int totalBatches = (int) Math.ceil((double) msgList.size() / batchSize);

        for (int i = 0; i < totalBatches; i++) {
            // 计算当前批次的起始和结束索引
            int start = i * batchSize;
            int end = Math.min(start + batchSize, msgList.size());

            // 获取当前批次的消息列表子集
            List<StockMsg> subList = msgList.subList(start, end);

            // 发送当前批次的消息
            DingTalkUtil.send(null, "TEST:" + JSON.toJSONString(subList));
        }

        restResult.setSuccess(true);
        return restResult;


    }

    @Data
    public static class StockMsg {

        private String stockName;
        @Column
        private String stockNum;
        @Column
        private String date;
        @Column
        private String reason;
        @Column(precision = 10, scale = 3)
        private double closePrice;
        @Column
        private int statusCode;

        private double k;
        private double d;
        private double j;
        private double dif;
        private double dea;
        private double macd;
//        private double rsi6;
//        private double rsi12;
//        private double rsi24;
        private double cci;
    }

}
